package io.github.uicdb.flame_driven;

import com.mojang.datafixers.util.Pair;
import net.minecraft.core.BlockPos;
import net.minecraft.network.protocol.Packet;
import net.minecraft.network.protocol.game.ClientGamePacketListener;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.Mth;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraftforge.items.CapabilityItemHandler;
import org.jetbrains.annotations.NotNull;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicReference;

public class ModUtil {
    public static final String MODID="flame_driven";
    public static ResourceLocation modLoc(String path) {
        return new ResourceLocation(MODID, path);
    }
    public static String modStr(String path) {
        return MODID+':'+path;
    }
    public static ResourceLocation forgeLoc(String path) {
        return new ResourceLocation("forge", path);
    }
    @SuppressWarnings("unchecked")
    public static <G> Class<G> castClass(Class<?> cls)
    {
        return (Class<G>) cls;
    }

    public static <T> T luckDraw(List<Pair<T,Double>> listIn, T defaultValue){
        var random=Math.random();
        for (Pair<T, Double> pair : listIn) {
            if (random<pair.getSecond()) {
                return pair.getFirst();
            }
        }
        return defaultValue;
    }
    public static <T> List<Pair<T,Double>> modifyChanceList(List<Pair<T,Double>> pairList){
        var allChoice=pairList.stream().map(Pair::getSecond).reduce(Double::sum).get();
        AtomicReference<Double> last= new AtomicReference<>((double) 0);
        return pairList.stream().sorted(Comparator.comparingDouble(Pair::getSecond)).map(tDoublePair -> {
            var rate= tDoublePair.getSecond() / allChoice;
            var result= Mth.clamp(last.get()+rate,0,1);
            last.set(result);
            return  new Pair<>(tDoublePair.getFirst(),result);
        }).sorted((o1, o2) -> Objects.equals(o1.getSecond(), o1.getSecond()) ? 0 : o1.getSecond() > o2.getSecond() ? 1 : -1).toList();
    }
    public static void sendBEUpdate(BlockEntity be, Packet<ClientGamePacketListener> packet){
        var level=be.getLevel();
        var pos=be.getBlockPos();
        if (level != null&&!level.isClientSide) {
            if (level.hasChunkAt(pos)){
                LevelChunk levelChunk= level.getChunkAt(pos);
                levelChunk.setUnsaved(true);
                Objects.requireNonNull(level.getServer()).getPlayerList().getPlayers().forEach(serverPlayer -> {
                    serverPlayer.connection.send(packet);
                });
            }
        }
    }
    public static void sendBEUpdate(BlockEntity be){
        sendBEUpdate(be,be.getUpdatePacket());
    }
    public static InteractionResult takeOrInsertItem(Level pLevel, @NotNull BlockPos pPos, @NotNull Player pPlayer, @NotNull InteractionHand pHand, int inputSlot, int sizePut) {
        if(pLevel.isClientSide)return InteractionResult.SUCCESS;
        var be= pLevel.getBlockEntity(pPos);
        if(be!=null){
            be.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY).ifPresent(iItemHandler -> {
                if(pPlayer.isShiftKeyDown()) {
                    List<Integer> nonEmptySlots = new ArrayList<>();
                    for (int index = 0; index < iItemHandler.getSlots(); index++) {
                        ItemStack what = iItemHandler.getStackInSlot(index);
                        if (!what.isEmpty()) nonEmptySlots.add(index);
                    }
                    if (!nonEmptySlots.isEmpty()) {
                        nonEmptySlots.forEach(slot -> {
                            pPlayer.addItem(iItemHandler.extractItem(slot, iItemHandler.getStackInSlot(slot).getCount(), false));
                        });
                    }
                }else {
                    var item = pPlayer.getItemInHand(pHand);
                    var result = iItemHandler.insertItem(inputSlot, item.split(sizePut), false);
                    item.grow(result.getCount());
                }
            });
        }
        return InteractionResult.SUCCESS;
    }
}
